パソコン活用研究ラピュタへの道(アセンブラ、DOS、Windows、旧型PCの活用研究)
FM-7/8 Subシステムメンテナンスコマンド
===============================================================================================
FM-7/8 は究極の8BitCPUと言われた6809をメイン用とサブ用に2個もち、メモリーもメイン用、サブ用に64Kを2個
持った、当時としては超ド級戦艦のパソコンでした。
サブシステムは主に、画面制御(とキーボード管理)の役割を持ち、メインシステムとは独立して動いているもので
一般的なプログラムではまったくブラックボックスとしての存在でしたが、FM-7/8の性能を極限まで引き出すには、この
サブシステムを直接コントロールする裏技もありました。->これがメンテナンスコマンド
パソコンの勉強の教材としては、このサブシステムのコントロールは非常にいい教材であったと思います。
すばらしいエミュレーターによりWindows上にFM-7/8が復活したので、ちょっとSubシステムの活用とメンテナンスコマンド
について思い出したことを書いてみたいと思います。あまり有用な情報ではありませんが、何かの役にたてば幸いです。
多くの部分を過去の記憶にたよっていますので、誤りがあるかもしれませんが、ご容赦下さい。
================================================================================================
1 Subシステム概要
メンテナンスコマンドの使用に当たり、FM-7/8のSubシステムについて知っておいた方がいいことを簡単にまとめておきます。
Subシステムは、メインシステムとは独立したもので、サブ専用のサブCPU(6809)により制御されています。主に画面制御
(とキーボード管理)をしています。
Subシステムの概念図
【メインCPU】<-->【共有RAM】<-->【サブCPU】<-->【V-RAM(サブのメモリ$0000-$C000)】<-->【CRTC】-表示->【CRT】
|
【コンソールバッファ/キャラクタROM】
Subシステムは128バイトの共有RAMを通じて、メインシステムとつながっています。メイン側の$FC80〜$FCFFがサブ側の
$D380〜$D3FFと共有されており、同じデータがこの領域に現れます。メインとサブ間のデータのやりとりはこの共有RAMを
通して行われます。
FM-7/8で何かを表示したい時は、
(A) メインからこの共有RAMを通して、表示のコマンドと表示するデータをサブに送る
(B) サブシステムは、データをサブメモリ(V-RAM)に書き込む
(C) CRTCがディスプレイに表示する
というような流れになります。
いささか面倒な流れに感じるかもしれませんが、サブシステムに表示コマンドとデータを送ってしまえば、画面制御はサブに
まかせて、メインは自分の次の仕事にとりかかれるので、うまく分業体制がくめる(=処理速度が速い)というメリットがありました。
当時の他の8ビットパソコンでは、ひとつのCPUがメインのコマンド処理も画面処理も仕切っていましたので、グラッフィックの処理が
非常に遅かったのですが、FM-7/8では画面制御をサブ側に任せたので、グラフィック処理速度が非常に高速になりました。
(といっいっても、BASICで組んだプログラムではかなり遅かった)
CRTCはCRTコントローラといって、V-RAM上のデータにもとずき、ディスプレイに実際の文字、グラフィックを表示する装置です。
2 Subシステムの動作
メインシステムとサブシステムは共有RAMの他に、HALT信号線、Busy信号線で接続されており、これらの信号線で同期を
とるようになっています。
さて、この同期をとるというのがいささかFM-7/8のメイン-サブという2個独立システムの制御の面倒な点です。
サブシステムで使われているメモリーは一般的なメモリー(普通PCで使うメモリー)なので、メインとサブが両方同時にアクセス
するということはできません(のはず)。すなわち片方が共有RAMにアクセスしている時は、他方は待機していなければなり
ません。
また、サブシステムが共有RAM上のデータを参照しながら処理している最中に、メインシステムが共有RAMのデータを書き換えたら
サブシステムは、正しい処理が行えません。
それで、FM-7/8では、メインとサブで同期をとって処理を進めるようになっています。その時に、HALT信号線、Busy信号線を
使います。
Busy信号線は、サブシステムのI/OからメインのI/Oにつながっており、サブからメインにReady/Busyを知らせるものです。
サブシステムはメインからのコマンド待ち状態のときReady、コマンドの処理にジャンプする直前にBusyに切り替えます。
メイン側ではこの信号線は$FD05の最上位ビットを参照することになります。最上位ビットが1の時はBusy、0の時はReadyです。
従って、メイン側は$FD05の最上位ビットを見て、0(Ready)の時に共有RAMにアクセスしてコマンドを送ります。
HALT信号線はメインのI/OからサブCPUのHALT入力につながっている線で、サブシステムを強制的に止めるものです。
メイン側の$FD05の最上位ビットを1にセットすると、HALT信号を発生し、サブシステムを強制的に停止します。最スタート
する時は、$FD05の最上ビットを0にします。
以上により、メイン側からサブ側にコマンドを送る作業の流れは以下のようになります。
(A) サブがBusyなら待機。Reday($FD05が0)になるまで待つ。
(B) サブがReadyになったら、サブをHALT($FD05の最上位ビットに1をセット)
(C) サブがReady($FD05が0)であることを確認
(D) 共有RAMにコマンドをセット
(E) サブを再スタート($FD05に0をセット)
なお、共有RAMに何もコマンドを設定せず、サブシステムを再スタートさせる時は、何もコマンドを設定していない印として
メインの$FC80(=サブの$D380)の最上ビットを1にセットします。(上記Dの作業の代わり)
3 サブシステムメンテナンスコマンド
サブシステムメンテナンスコマンドはメインからサブシステムの動作チェックをするために用意された命令です。
このコマンドは一般的なプログラマからの使用を想定されたものではありませんでしたが、FM-7/8で高速ゲーム
を作るには必須の裏技となりました。(FMパワーユーザーへの登竜門的な技でしたねえ。なつかし)
コマンドコードは$3Fです。サブシステムへのコマンドは共有RAMの$FC82(サブ側の$D382)に書き込みます。
コマンドコード$3Fに続けて8バイトのキーワードを指定します。キーワードはFM-8では'YAMAUCHI'(これが通称YAMUUCHI
コマンドといわれる所以です)です。FM-7では任意のデータでO.K.です。
キーワードに続けてサブコマンドを指定します。
サブコマンドは4個あります。
T $90 メンテナンスコマンド終了
U $91 <転送元> <転送先> <転送バイト数> ブロック転送サブコマンド
V $92 <アドレス> サブコマンド列のアドレス変更
W $93 <アドレス> 指定アドレスへサブルーチンコール JSR <アドレス> と同義になります。
実例は4.サンプルプログラムで見てください。
4 サンプルプログラム
サンプルプログラムはFM-7/8エミュレーター(ROM抜き)で使う、サブシステムのROMを抜いてくるプログラムです。
サブシステムのROM領域($D800〜$FFFF)を抜いてきて、メイン側の$2000〜$4FFFにいったんため込み、その後RS232Cで
シリアル転送するプログラムです。
100行目で1000行目以降のサブルーチンをコールします。
1000〜1030行のサブルーチンでは、上記のサブの制御(A)から(C)の作業を行います。(サブがReadyになるのを待ち、サブをHALT)
110〜130行目で、サブシステムメンテナンスコマンドを共有RAM(メイン側$FC82から)に書き込んでいます。
メンテナンスコマンドは以下の通り。
サブコマンド(ブロック転送 $91)により、$FCC0(サブの$D3C0)からの$40バイト(64バイト)の領域に、サブシステムの
ROM領域($D800〜)のROMデータを
転送してきます。
アドレス | メインFC82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 8A | 8B | 8C | 8D | 8F | 90 | 91 | 92 | 93 | FCC0〜 |
アドレス | サブD382 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 8A | 8B | 8C | 8D | 8F | 90 | 91 | 92 | 93 | D3C0〜 |
データ | 3F | 59 | 41 | 4D | 41 | 55 | 43 | 48 | 49 | 91 | D8 | 00 | D3 | C0 | 00 | 40 | 90 | |
メンテナンス コマンド |
Y | A | M | A | U | C | H | I | ブロック 転送 |
転送元 | 転送先 | 転送 バイト数 |
サブコマンド 終了 |
転送データ |
140行目で、サブシステム再スタート
160〜180行目では、共有RAMの$FCC0(サブ$D3C0)からの64バイトのデータをメインの$2000以降に転送しています。
230〜250行目。転送元のアドレスの指定値(共有RAMメイン側$FC8C,$FC8Dの値)を$40進めます。これで、$40(64)バイト
づつサブROMのデータを順次取得していきます。$FFFFまで取得すると300行目以降の、RS232Cシリアル転送の作業に
移行します。
(RS232Cシリアル転送の説明は省略します)
10 CLEAR 300,&H2000:AD=&H2000:CLS 20 DIM D%(20) 30 FOR I=0 TO 16 40 READ A$: D%(I)=VAL(A$) 50 NEXT 55 ' Sub System Maintainance Command 60 DATA &H3F,&H59,&H41,&H4D,&H41,&H55,&H43,&H48,&H49,&H91,&HD8,&H00,&HD3,&HC0,&H00,&H40,&H90 100 GOSUB 1000'SUB SYSTEM HALT 110 FOR I=0 TO 16 120 POKE &HFC82+I,D%(I) 130 NEXT 140 POKE &HFD05,0 'START 150 GOSUB 1000 160 FOR I=0 TO &H3F 170 POKE AD+I,PEEK(&HFCC0+I) 180 NEXT 190 AD=AD+&H40 200 POKE &HFC80,PEEK(&HFC80) OR &H80 210 POKE &HFD05,0 220 LOCATE 1,10:PRINT HEX$(D%(10)*256+D%(11)+&H3F) 230 D%(11)=D%(11)+&H40 240 IF D%(11)>&HFF THEN D%(11)=0:D%(10)=D%(10)+1 250 IF D%(10)>&HFF THEN GOTO 300 ELSE GOTO 100 300 PRINT"SEND SUB SYSTEM ROM Y or N"; 310 C$=INPUT$(1) 320 IF C$="y" OR C$="Y" THEN GOTO 400 330 IF C$="n" OR C$="N" THEN END 340 GOTO 310 400 OPEN "O",#1,"COM0:S8N1" 420 FOR I=&H2000 TO &H47FF 430 PRINT #1,CHR$(PEEK(I)); 440 LOCATE 1,13:PRINT I-&H1FFF 450 NEXT 460 CLOSE 470 PRINT:PRINT"COMPLETE" 480 END 1000 IF (PEEK(&HFD05)AND &H80)<>0 THEN 1000 'BUSY CHECK 1010 POKE &HFD05,&H80 'HALT 1020 IF (PEEK(&HFD05)AND &H80)=0 THEN 1020 'READY CHECK 1030 RETURN |